<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  <script src="wct-browser-config.js"></script>
  <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>

<script type="module">
window.clearTestLists = function() {
  window.actualAttachedList = [];
  window.actualReadyList = [];
  window.actualReadyBeforeAttachedList = [];
};

window.clearTestLists();

window.readyBehavior = {
  properties: {
    prop: {
      value: true,
      observer: '_propChanged'
    },
  },
  _propChanged: function() {
    this.observerShadowRoot = Boolean(this.shadowRoot);
  },
  ready: function() {
    this._readied = true;
    this.readyList = window.actualReadyList.slice();
    this.readyShadowRoot = Boolean(this.shadowRoot);
    window.actualReadyList.push(this);
  },

  attached: function() {
    this.attachedShadowRoot = Boolean(this.shadowRoot);
    this.attachedTime$Keys = Object.keys(this.$);
    this.attachedList = window.actualAttachedList.slice();
    window.actualAttachedList.push(this);
    if (!this._readied) {
      window.actualReadyBeforeAttachedList.push(this);
    }
  }
};
</script>

<dom-module id="x-zot">
  <template>
    x-zot<slot></slot>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-zot',
  behaviors: [window.readyBehavior]
});
</script>
</dom-module>

<dom-module id="x-bar">
  <template>
    <x-zot id="zot"></x-zot>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-bar',
  behaviors: [window.readyBehavior]
});
</script>
</dom-module>

<dom-module id="x-foo">
  <template>
    <x-bar id="bar1"></x-bar>
    <x-bar id="bar2"></x-bar>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-foo',
  behaviors: [window.readyBehavior]
});
</script>
</dom-module>

<dom-module id="x-ready">
  <template>
    <x-zot id="a">
      <x-zot id="b"></x-zot>
      <x-zot id="c">
        <x-zot id="d"></x-zot>
      </x-zot>
    </x-zot>
    <x-foo id="foo"></x-foo>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-ready',
  properties: {
    foo: {
      observer: '_fooChanged'
    }
  },
  behaviors: [window.readyBehavior],
  _fooChanged: function() {}
});
</script>
</dom-module>

<dom-module id="x-templatized">
  <template>
    <template is="dom-if" if>
      <x-ready foo="[[foo]]"></x-ready>
    </template>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-templatized',
  properties: {
    foo: {
      value: 'foo'
    }
  }
});
</script>
</dom-module>

<script type="module">
import { flush } from '../../lib/utils/flush.js';

suite('ready and attached ordering', function() {

  let el;

  setup(function() {
    window.clearTestLists();
    el = document.createElement('x-ready');
    document.body.appendChild(el);
  });

  teardown(function() {
    document.body.removeChild(el);
  });

  test('element dom ready before element', function() {
    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);
    var foo = el.$.foo;
    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);
    var b1 = foo.$.bar1, b2 = foo.$.bar2;
    assert.includeMembers(b1.readyList, [b1.$.zot]);
    assert.includeMembers(b2.readyList, [b2.$.zot]);
  });

  // test('element dom connected before element', function() {
  //   assert.includeMembers(el.attachedList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);
  //   var foo = el.$.foo;
  //   assert.includeMembers(foo.attachedList, [foo.$.bar1, foo.$.bar2]);
  //   var b1 = foo.$.bar1, b2 = foo.$.bar2;
  //   assert.includeMembers(b1.attachedList, [b1.$.zot]);
  //   assert.includeMembers(b2.attachedList, [b2.$.zot]);
  // });

  test('shadowRoot available in ready, connected, observer', function() {
    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,
      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,
      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {
      assert.isTrue(e.observerShadowRoot);
      assert.isTrue(e.readyShadowRoot);
      assert.isTrue(e.attachedShadowRoot);
    });
  });

  test('element attached called after ready', function() {
    assert.equal(window.actualReadyBeforeAttachedList.length, 0);
  });

  test('element has $ references at attached time', function() {
    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);
    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);
  });

});

suite('templatized: ready and attached ordering', function() {

  let container, el;

  setup(function() {
    window.clearTestLists();
    container = document.createElement('x-templatized');
    document.body.appendChild(container);
    flush();
    el = container.shadowRoot.querySelector('x-ready');
  });

  teardown(function() {
    document.body.removeChild(container);
  });

  test('element dom ready before element', function() {
    assert.includeMembers(el.readyList, [el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo]);
    var foo = el.$.foo;
    assert.includeMembers(foo.readyList, [foo.$.bar1, foo.$.bar1.$.zot, foo.$.bar2, foo.$.bar2.$.zot]);
    var b1 = foo.$.bar1, b2 = foo.$.bar2;
    assert.includeMembers(b1.readyList, [b1.$.zot]);
    assert.includeMembers(b2.readyList, [b2.$.zot]);
  });

  test('shadowRoot available in ready, connected, observer', function() {
    [el, el.$.a, el.$.b, el.$.c, el.$.d, el.$.foo,
      el.$.foo.$.bar1, el.$.foo.$.bar1.$.zot,
      el.$.foo.$.bar2, el.$.foo.$.bar2.$.zot].forEach((e) => {
      assert.isTrue(e.observerShadowRoot);
      assert.isTrue(e.readyShadowRoot);
      assert.isTrue(e.attachedShadowRoot);
    });
  });

  test('element attached called after ready', function() {
    assert.equal(window.actualReadyBeforeAttachedList.length, 0);
  });

  test('element has $ references at attached time', function() {
    assert.sameMembers(el.attachedTime$Keys, ['a', 'b', 'c', 'd', 'foo']);
    assert.sameMembers(el.$.foo.attachedTime$Keys, ['bar1', 'bar2']);
  });

});
</script>
</body>
</html>
